// VBSParse.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <stdio.h>
#include <activscp.h>
#include <new>

#include <wchar.h>


const GUID CLSID_VBScript = {0xb54f3741, 0x5b07, 0x11cf, {0xa4, 0xb0, 0x00, 0xaa, 0x00, 0x4a, 0x55, 0xe8}};
const GUID CLSID_JScript  = {0xf414c260, 0x6ac0, 0x11cf, {0xb6, 0xd1, 0x00, 0xaa, 0x00, 0xbb, 0xbb, 0x58}};

class MySite : public IActiveScriptSite {
private:

  ULONG m_cref;
  virtual ~MySite() {}

public:

  MySite() {
    this->m_cref = 1;
  }

  STDMETHOD_(ULONG, AddRef)() {
    return ++this->m_cref;
  }

  STDMETHOD_(ULONG,Release)() {
    --this->m_cref;
    if (this->m_cref == 0) {
      delete this;
      return 0;
    }
    return this->m_cref;
  }

  STDMETHOD(QueryInterface)(REFIID iid, void ** ppv) {
    if (ppv == NULL)
      return E_POINTER;
    if (IsEqualIID(iid, IID_IUnknown))
      *ppv = (IUnknown*)this;
    else if (IsEqualIID(iid, IID_IActiveScriptSite))
      *ppv = (IActiveScriptSite*)this;
    else {
      *ppv = NULL;
      return E_NOINTERFACE;
    }
    this->AddRef();
    return S_OK;
  }

  STDMETHOD(GetLCID)(LCID * plcid) {
    return E_NOTIMPL;
  }

  STDMETHOD(GetItemInfo)(
    LPCOLESTR pstrName,
    DWORD dwReturnMask,
    IUnknown ** ppunkItem,
    ITypeInfo ** ppti) {
    return E_NOTIMPL;
  }

  STDMETHOD(GetDocVersionString)(BSTR * pbstrVersion) {
    return E_NOTIMPL;
  }

  STDMETHOD(OnScriptTerminate)(
    const VARIANT * pvarResult,
    const EXCEPINFO * pexcepinfo) {
    return S_OK;
  }

  STDMETHOD(OnStateChange)(SCRIPTSTATE state) {
    return S_OK;
  }

  STDMETHOD(OnEnterScript)() {
    return S_OK;
  }
 
  STDMETHOD(OnLeaveScript)() {
    return S_OK;
  }

  STDMETHOD(OnScriptError)(IActiveScriptError * perror) {
    EXCEPINFO excepinfo;
    LONG column = 0;
    ULONG line = 0;
    DWORD context = 0;
    BSTR bstrLine = NULL;
    memset(&excepinfo, 0x00, sizeof excepinfo);
    perror->GetExceptionInfo(&excepinfo);
    if (excepinfo.pfnDeferredFillIn != NULL)
      excepinfo.pfnDeferredFillIn(&excepinfo);
    perror->GetSourceLineText(&bstrLine);
    perror->GetSourcePosition(&context, &line, &column);

    wprintf(L"Error on line %ld column %ld\n", line, column);
    if (bstrLine != NULL)
      wprintf(L"Line: %s\n", bstrLine);
    if (excepinfo.bstrDescription != NULL)
      wprintf(L"Description: %s\n", excepinfo.bstrDescription);
    if (excepinfo.bstrSource != NULL)
      wprintf(L"Source: %s\n", excepinfo.bstrSource);
    if (excepinfo.bstrHelpFile != NULL)
      wprintf(L"Help: %s\n", excepinfo.bstrHelpFile);

    SysFreeString(bstrLine);
    SysFreeString(excepinfo.bstrDescription);
    SysFreeString(excepinfo.bstrSource);
    SysFreeString(excepinfo.bstrHelpFile);

    return S_OK;
  }
};

void main(int argc, char* argv[]) {
  HRESULT hr = S_OK;
  HRESULT hrInit;
  IClassFactory * pfactory = NULL;
  IActiveScript * pscript = NULL;
  IActiveScriptParse * pparse = NULL;
  IActiveScriptSite * psite = NULL;

  FILE *fp;
  long len;
  char *buf;
  LPOLESTR pszW;

  if (argc != 2)
  {
	  printf("VBSParse filename.vbs");
	  goto LDone;
  }

  hr = hrInit = OleInitialize(NULL);
  if (FAILED(hr))
    goto LError;

  hr = CoGetClassObject(CLSID_VBScript, CLSCTX_SERVER, NULL, 
    IID_IClassFactory, (void**)&pfactory);
  if (FAILED(hr))
    goto LError;

  hr = pfactory->CreateInstance(NULL, IID_IActiveScript, (void**)&pscript);
  if (FAILED(hr))
    goto LError;

  psite = new(std::nothrow) MySite();
  if (psite == NULL) {
    hr = E_OUTOFMEMORY;
    goto LError;
  }

  hr = pscript->SetScriptSite(psite);
  if (FAILED(hr))
    goto LError;

  hr = pscript->QueryInterface(IID_IActiveScriptParse, (void**)&pparse);
  if (FAILED(hr))
    goto LError;

  // Open Filename and read contents into string
  fp = fopen(argv[1], "rb");
  fseek(fp,0,SEEK_END);		// Go to end
  len = ftell(fp);			// Get position at end (length)
  fseek(fp,0,SEEK_SET);		// Go to begining
  buf = (char *)malloc(len+1);// Allocate the buffer for the file
  fread(buf,len,1,fp);		// Read into buffer
  buf[len] = 0;				// Make it easier to find the end of the string
  fclose(fp);
  
  // Convert file in buffer to unicode
  pszW = (LPOLESTR)malloc(len*2+2);
  MultiByteToWideChar(CP_ACP, 0, buf, len, pszW, len);
  pszW[len] = 0;

  hr = pparse->ParseScriptText((LPCOLESTR)pszW,
    NULL, NULL, NULL, 0, 1, 0, NULL, NULL);

  free(buf);
  free(pszW);
  
  if (FAILED(hr))
    goto LError;
 
LError:

  if (FAILED(hr))
    printf("%0x\n", hr);

  if (pparse != NULL)
    pparse->Release();

  if (psite != NULL)
    psite->Release();

  if (pscript != NULL) {
    pscript->Close();
    pscript->Release();
  }

  if (pfactory != NULL)
    pfactory->Release();

  if (SUCCEEDED(hrInit))
    OleUninitialize();

LDone:
  ;

}



